from manimlib import *
import numpy as np
import sys, os

__curr_dir = os.path.dirname(__file__)
if __curr_dir not in sys.path:
    sys.path.append(__curr_dir)
from MySpring import *

FONT_SIZE = 35
youngs_modules = 1  # KN/m2

REPEAT = 1


class FEMScene(Scene):
    def construct(self):
        """
        1. 生成一段[0,0,0]到[1,0,0]的弹簧
        2. 并压缩到[0.8,0,0]
        3. 显示F和u
        """
        axis = ThreeDAxes()
        O_axes_label = Text("O")
        X_axes_label = Text("X")
        X_axes_label.shift(np.array([4.1, 0, 0]))
        Y_axes_label = Text("Y")
        Y_axes_label.shift(np.array([0, 3.1, 0]))
        fake_axes = Group(
            Arrow([0, 0, 0], [4, 0, 0]),
            Arrow([0, 0, 0], [0, 3, 0]),
            O_axes_label,
            X_axes_label,
            Y_axes_label,
        )
        fake_axes.to_corner(LEFT + DOWN)
        fake_axes.shift([-3.5, -2, 0])

        frame = self.camera.frame
        frame.set_height(12)

        # ========================================================
        # ========================================================
        # ========================================================
        # 创建弹簧
        sprint_start = [0, 0, 0]
        sprint_end = [10, 0, 0]
        spring = Spring3D(sprint_start, sprint_end, axis)
        spring.center()  # 置于中间

        # ========================================================
        # ========================================================
        # ========================================================

        # 绘制文字
        level_0_text = Text(
            "Level 0: Hook's Law + single spring",
            t2c={
                "+ single spring": GREEN,
            },
        )
        level_0_text.to_corner(LEFT + UP)
        level_0_text.shift(LEFT + UP)
        level_0_text.shift(LEFT + UP)
        spring_constant = Tex("spring\enspace constant\enspace k\enspace =\enspace 1kN/m")
        negtive_tag = Tex("Compression\enspace is\enspace Negtive")
        extra_info_group = VGroup(
            spring_constant,
            negtive_tag,
        )
        extra_info_group.arrange(DOWN)
        extra_info_group.to_corner(RIGHT + UP)
        extra_info_group.shift(RIGHT + UP)
        extra_info_group.shift(RIGHT + UP)

        hooks_law = Tex("F=k\delta{L}")
        hooks_law.align_to(level_0_text, LEFT + UP)
        hooks_law.shift(DOWN)
        hooks_law.scale(1.5)

        self.play(ShowCreation(level_0_text))
        self.play(ShowCreation(hooks_law))

        self.wait(3)
        self.play(ShowCreation(fake_axes))
        self.play(ShowCreation(extra_info_group))

        self.wait(3)

        # ========================================================
        # ========================================================
        # ========================================================

        # 绘制宽度括号
        brace = always_redraw(Brace, spring, UP)
        brace.set_style(stroke_width=0.3)
        # 绘制括号标签
        _, brace_number1 = brace_label1 = VGroup(
            Tex(
                "\delta{L} = \delta{u_1}-\delta{u_2} = ",
                font_size=FONT_SIZE,
            ),
            DecimalNumber(
                0,
                show_ellipsis=False,
                num_decimal_places=2,
                include_sign=False,
                font_size=FONT_SIZE,
            ),
        )
        brace_label1.arrange(RIGHT)
        # 更新位置
        always(brace_label1.next_to, brace, UP)
        # 更新数字
        f_always(brace_number1.set_value, lambda: 0.1 * spring.get_width() - 1)

        # 绘制括号标签
        _, brace_number2 = brace_label2 = VGroup(
            Tex(
                "L = ",
                font_size=FONT_SIZE,
            ),
            DecimalNumber(
                0,
                show_ellipsis=False,
                num_decimal_places=2,
                include_sign=False,
                font_size=FONT_SIZE,
            ),
        )
        brace_label2.arrange(RIGHT)
        # 更新位置
        always(brace_label2.next_to, brace_label1, UP)
        # 更新数字
        f_always(brace_number2.set_value, lambda: 0.1 * spring.get_width())

        # ========================================================
        # ========================================================
        # ========================================================

        # 绘制箭头
        node1 = spring[1]
        node2 = spring[2]

        left_arrow = Arrow(start=node1.get_center() - np.array([1.5, 0, 0]), end=node1)
        left_arrow.set_style(stroke_color=RED)
        always(left_arrow.next_to, node1, LEFT)
        right_arrow = Arrow(start=node2.get_center() + np.array([1.5, 0, 0]), end=node2)
        right_arrow.set_style(stroke_color=RED)
        always(right_arrow.next_to, node2, RIGHT)

        # ========================================================
        # ========================================================
        # ========================================================

        # 绘制左F
        F_left, F_left_number = F_left_label = VGroup(
            Tex(
                "F_{left} = ",
                font_size=FONT_SIZE,
                t2c={"F_{left}": RED},
            ),
            DecimalNumber(
                0,
                show_ellipsis=False,
                num_decimal_places=2,
                include_sign=False,
                font_size=FONT_SIZE,
            ),
        )
        F_left_label.arrange(RIGHT)
        # 更新位置
        always(F_left_label.next_to, left_arrow, LEFT)
        # 更新数字
        f_always(F_left_number.set_value, lambda: (0.1 * spring.get_width() - 1) * youngs_modules)

        # ========================================================
        # ========================================================
        # ========================================================

        # 绘制右F
        F_right, F_right_number = F_right_label = VGroup(
            Tex(
                "F_{right} = ",
                font_size=FONT_SIZE,
                t2c={"F_{right}": RED},
            ),
            DecimalNumber(
                0,
                show_ellipsis=False,
                num_decimal_places=2,
                include_sign=False,
                font_size=FONT_SIZE,
            ),
        )
        F_right_label.arrange(RIGHT)
        # 更新位置
        always(F_right_label.next_to, right_arrow, RIGHT)
        # 更新数字
        f_always(F_right_number.set_value, lambda: -(0.1 * spring.get_width() - 1) * youngs_modules)

        # ========================================================
        # ========================================================
        # ========================================================

        # 绘制左u
        u_left, u_left_number = u_left_label = VGroup(
            Tex(
                "\delta{u_{left}} = ",
                font_size=FONT_SIZE,
            ),
            DecimalNumber(
                0,
                show_ellipsis=False,
                num_decimal_places=2,
                include_sign=False,
                font_size=FONT_SIZE,
            ),
        )
        u_left_label.arrange(RIGHT)
        # 更新位置
        always(u_left_label.next_to, F_left_label, DOWN)
        # 更新数字
        f_always(u_left_number.set_value, lambda: -(0.1 * spring.get_width() - 1) * 0.5)

        # ========================================================
        # ========================================================
        # ========================================================

        # 绘制右u
        u_right, u_right_number = u_right_label = VGroup(
            Tex(
                "\delta{u_{right}} = ",
                font_size=FONT_SIZE,
            ),
            DecimalNumber(
                0,
                show_ellipsis=False,
                num_decimal_places=2,
                include_sign=False,
                font_size=FONT_SIZE,
            ),
        )
        u_right_label.arrange(RIGHT)
        # 更新位置
        always(u_right_label.next_to, F_right_label, DOWN)
        # 更新数字
        f_always(u_right_number.set_value, lambda: (0.1 * spring.get_width() - 1) * 0.5)

        spring_group = Group(
            spring,
            brace,
            brace_label1,
            brace_number1,
            brace_label2,
            brace_number2,
            # node 1
            left_arrow,
            F_left_label,
            F_left_number,
            u_left_label,
            u_left_number,
            # node 2
            right_arrow,
            F_right_label,
            F_right_number,
            u_right_label,
            u_right_number,
        )
        # 加入到绘制
        self.play(ShowCreation(spring_group))


        self.wait(3)
        # ========================================================
        # ========================================================
        # ========================================================

        # self.wait(5)
        for i in range(REPEAT):
            # 弹簧压缩
            self.play(
                spring.animate.stretch(0.8, 0, about_point=axis.c2p(sprint_start[0], sprint_start[1], sprint_start[2])),
                run_time=3,
            )
            # self.wait(3)

            # 弹簧拉伸
            self.play(
                spring.animate.stretch(1.5, 0, about_point=axis.c2p(sprint_start[0], sprint_start[1], sprint_start[2])),
                run_time=3,
            )
            # self.wait(3)

            # 弹簧拉伸
            self.play(
                spring.animate.stretch(
                    5 / 6, 0, about_point=axis.c2p(sprint_start[0], sprint_start[1], sprint_start[2])
                ),
                run_time=3,
            )
            self.wait(3)

        # ========================================================
        # ========================================================
        # ========================================================
        self.play(Uncreate(extra_info_group))

        level_1_text = Text(
            "Level 1: Hook's Law + single spring + node",
            t2c={
                "+ single spring": GREEN,
                "+ node": RED,
            },
        )
        level_1_text.align_to(level_0_text, LEFT + UP)

        self.play(ReplacementTransform(level_0_text, level_1_text))

        self.wait(2)

        # 节点编号
        corner1 = node1.get_center() + np.array([1, -2, 0])
        node1_tip_arrow = Arrow(start=corner1, end=node1, stroke_width=3)
        node1_tip_line = Line(start=corner1, end=corner1 + np.array([3, 0, 0]), stroke_width=3)
        node1_tip = Text("node #1").next_to(node1_tip_line, UP)

        corner2 = node2.get_center() + np.array([-1, -2, 0])
        node2_tip_arrow = Arrow(start=corner2, end=node2, stroke_width=3)
        node2_tip_line = Line(start=corner2, end=corner2 + np.array([-3, 0, 0]), stroke_width=3)
        node2_tip = Text("node #2").next_to(node2_tip_line, UP)
        node_tips = [
            node1_tip_arrow,
            node1_tip_line,
            node1_tip,
            node2_tip_arrow,
            node2_tip_line,
            node2_tip,
        ]
        self.play(*[ShowCreation(mob) for mob in node_tips])
        self.wait(2)

        # ========================================================
        # ========================================================
        # ========================================================

        # right变1，left变2
        F_1 = Tex("F_1 = ", font_size=FONT_SIZE, t2c={"F_1": RED})
        F_1.set_x(F_left.get_x())
        F_1.set_y(F_left.get_y())
        F_2 = Tex("F_2 = ", font_size=FONT_SIZE, t2c={"F_2": RED})
        F_2.set_x(F_right.get_x())
        F_2.set_y(F_right.get_y())
        u_1 = Tex("\delta{u_1} = ", font_size=FONT_SIZE)
        u_1.set_x(u_left.get_x())
        u_1.set_y(u_left.get_y())
        u_2 = Tex("\delta{u_2} = ", font_size=FONT_SIZE)
        u_2.set_x(u_right.get_x())
        u_2.set_y(u_right.get_y())
        self.play(
            Transform(F_left, F_1),
            Transform(u_left, u_1),
            Transform(F_right, F_2),
            Transform(u_right, u_2),
        )
        self.wait(2)

        self.play(*[Uncreate(mob) for mob in node_tips])

        # ========================================================
        # ========================================================
        # ========================================================

        self.play(
            Uncreate(fake_axes),
            Uncreate(spring_constant),
            Uncreate(negtive_tag),
            spring_group.animate.shift(DOWN).shift(DOWN).shift(DOWN).shift(DOWN),
        )
        self.wait(2)

        # 可写出以下式子

        self.play(hooks_law.animate.scale(2 / 3))
        dL = (
            VGroup(
                Tex(r"\delta{L}=\delta{u_1}-\delta{u_2}"),
                Tex(r"F_1=-F_2"),
            )
            .arrange(DOWN)
            .next_to(hooks_law, DOWN)
        )
        self.play(Write(dL))
        self.wait(2)

        single_spring_equation_align = VGroup(
            hooks_law,
            dL,
        )
        align_brace = always_redraw(Brace, single_spring_equation_align, RIGHT)
        self.play(Write(align_brace))
        self.wait(2)

        # 创建初始公式
        F1_equal = Tex(r"F_1=k(\delta{u_1} - \delta{u_2})")
        F2_equal = Tex(r"F_2=-k(\delta{u_1} - \delta{u_2})")
        formula_group = VGroup(F1_equal, F2_equal).arrange(DOWN)

        # 显示初始公式
        self.play(Write(formula_group))
        self.wait(2)
        self.play(formula_group.animate.move_to(align_brace.get_center() + np.array([3, 0, 0])))
        self.wait(2)

        # ========================================================
        # ========================================================
        # ========================================================

        # escalate 矩阵化
        level_2_text = Text(
            "Level 2: Hook's Law + single spring + node + matrix form",
            t2c={
                "+ single spring": GREEN,
                "+ node": RED,
                "+ matrix form": YELLOW,
            },
        )
        level_2_text.align_to(level_1_text, LEFT + UP)

        self.play(ReplacementTransform(level_1_text, level_2_text))
        self.wait(2)

        # 创建目标矩阵
        single_spring_k = Tex(
            r"\begin{bmatrix}  F_1  \\  F_2 \end{bmatrix} = k\begin{bmatrix} 1 & -1 \\  -1  &  1  \end{bmatrix} \begin{bmatrix}  \delta{u_1} \\   \delta{u_2}  \end{bmatrix}",
            color=RED,
        )
        # 将公式转换为矩阵形式
        self.play(Write(single_spring_k))
        self.wait(2)
        self.play(single_spring_k.animate.move_to(formula_group.get_center() + np.array([5, 0, 0])))
        self.wait(2)

        # 不可求解
        mat2 = Tex(
            r"k\begin{bmatrix} 1 & -1 \\ -1 & 1 \end{bmatrix}",
        )
        mat3 = Tex(
            r"k\begin{bmatrix} 0 & 0 \\ -1 & 1 \end{bmatrix}",
        )
        mat4 = Tex(
            r"det(k\begin{bmatrix} 0 & 0 \\ -1 & 1 \end{bmatrix}) = 0",
        )
        no_resolve_text = Text("No Solution!").scale(2)

        self.play(Write(mat2))
        self.wait(2)
        self.play(TransformMatchingTex(mat2, mat3))
        self.wait(2)
        self.play(TransformMatchingTex(mat3, mat4))
        self.wait(2)
        self.play(Uncreate(mat4), ShowCreation(no_resolve_text))
        self.wait(2)

        self.play(Uncreate(no_resolve_text))

        introduce_boundary_text = (
            Tex(r"Introducing\enspace boundary\enspace \delta{u_1} = 0").scale(1.5).shift(UP).shift(UP)
        )
        self.play(ShowCreation(introduce_boundary_text))
        self.wait(2)

        self.play(single_spring_k.animate.move_to(ORIGIN).scale(1.5))
        self.wait(2)

        # ========================================================
        # ========================================================
        # ========================================================

        # escalate 加入边界条件
        level_3_text = Text(
            "Level 3: Hook's Law + single spring + node + matrix form + boundary",
            t2c={
                "+ single spring": GREEN,
                "+ node": RED,
                "+ matrix form": YELLOW,
                "+ boundary": BLUE,
            },
        )
        level_3_text.align_to(level_2_text, LEFT + UP)
        self.play(ReplacementTransform(level_2_text, level_3_text))
        self.wait(2)

        fem_formular_with_boundray = Tex(
            r"\begin{bmatrix}   F_2 \end{bmatrix} = k\begin{bmatrix} 1  \end{bmatrix} \begin{bmatrix}  \delta{u_2}  \end{bmatrix}",
            color=RED,
        )
        self.play(ReplacementTransform(single_spring_k, fem_formular_with_boundray))
        self.wait(2)

        # 更新数字
        f_always(u_left_number.set_value, lambda: 0)
        f_always(u_right_number.set_value, lambda: 0.1 * spring.get_width() - 1)
        self.play(
            spring.animate.stretch(0.8, 0, about_point=node1.get_center()),
            # run_time=3,
        )
        self.wait(2)
        # self.wait(3)

        self.play(
            spring.animate.stretch(1.5, 0, about_point=node1.get_center()),
            # run_time=3,
        )
        self.wait(2)
        # self.wait(3)

        self.play(
            spring.animate.stretch(5 / 6, 0, about_point=node1.get_center()),
            # run_time=3,
        )
        self.wait(2)

        self.play(
            Uncreate(fem_formular_with_boundray),
            Uncreate(introduce_boundary_text),
            Uncreate(single_spring_equation_align),
            Uncreate(align_brace),
            Uncreate(formula_group),
        )
        self.wait(2)

        # ========================================================
        # ========================================================
        # ========================================================

        # escalate 多单元
        level_4_text = Text(
            "Level 4: Hook's Law + multiple spring + node + matrix form + boundary",
            t2c={
                "+ multiple spring": GREEN,
                "+ node": RED,
                "+ matrix form": YELLOW,
                "+ boundary": BLUE,
            },
        )
        level_4_text.align_to(level_3_text, LEFT + UP)
        self.play(ReplacementTransform(level_3_text, level_4_text))
        self.wait(2)

        # 在刚才的弹簧中加一个节点
        node3 = Sphere(radius=spring_group[0][1].radius, color=RED)
        spring_group.add(node3)
        # 更新位置
        always(node3.move_to, spring_group[0][0].get_center())
        self.play(ShowCreation(node3))
        self.wait(2)

        # node3 标签

        corner3 = node3.get_center() + np.array([-1, -2, 0])
        node3_tip_arrow = Arrow(start=corner3, end=node3, stroke_width=3)
        node3_tip_line = Line(start=corner3, end=corner3 + np.array([-3, 0, 0]), stroke_width=3)
        node3_tip = Text("node #3").next_to(node3_tip_line, UP)
        node3_tips = Group(
            node3_tip_arrow,
            node3_tip_line,
            node3_tip,
        )
        self.play(ShowCreation(node3_tips))
        self.wait(2)
        self.play(Uncreate(node3_tips))
        self.wait(2)

        mid_arrow31 = Arrow(
            start=node3,
            end=node3.get_center() - np.array([1.5, 0, 0]),
        )
        mid_arrow31.set_style(stroke_color=RED)
        always(mid_arrow31.next_to, node3, LEFT)

        # 绘制F31字
        F_31 = Tex(r"F_{31}", font_size=FONT_SIZE, color=RED)
        # 更新位置
        always(F_31.next_to, mid_arrow31, DOWN * 2)

        mid_arrow32 = Arrow(
            start=node3.get_center() + np.array([1.5, 0, 0]),
            end=node3,
        )
        mid_arrow32.set_style(stroke_color=RED)
        always(mid_arrow32.next_to, node3, RIGHT)

        # 绘制F32字
        F_32 = Tex(r"F_{32}", font_size=FONT_SIZE, color=RED)
        # 更新位置
        always(F_32.next_to, mid_arrow32, DOWN * 2)

        # ========================================================
        # ========================================================
        # ========================================================

        # 绘制u_3
        u_3 = Tex(r"\delta{u_{3}}", font_size=FONT_SIZE)
        # 更新位置
        always(u_3.next_to, node3, DOWN * 2)

        spring_group.add(F_31)
        spring_group.add(F_32)
        spring_group.add(mid_arrow31)
        spring_group.add(mid_arrow32)
        spring_group.add(u_3)

        self.play(
            ShowCreation(mid_arrow31),
            ShowCreation(mid_arrow32),
            ShowCreation(F_31),
            ShowCreation(F_32),
            ShowCreation(u_3),
        )
        self.wait(2)

        # ========================================================
        # ========================================================
        # ========================================================

        F3_equal_two_spring = Tex(r"F_3 = F_{31} + F_{32}")

        self.play(ShowCreation(F3_equal_two_spring))
        self.wait(2)
        self.play(F3_equal_two_spring.animate.shift([0, 4, 0]))
        self.wait(2)

        F1_equal_two_spring = Tex(r"F_1", "=", r"k(\delta{u_1} - \delta{u_3})")
        F31_equal_two_spring = Tex(r"F_{31}", "=", r"k(\delta{u_3} - \delta{u_1})")
        spring1_equal_group = VGroup(F1_equal_two_spring, F31_equal_two_spring)
        spring1_equal_group.arrange(DOWN)

        self.play(ShowCreation(spring1_equal_group))
        self.wait(2)
        self.play(spring1_equal_group.animate.shift([-5, 4, 0]))
        self.wait(2)

        spring1_k = Tex(
            r"\begin{bmatrix}  F_1  \\  F_{31} \end{bmatrix} ",
            "=",
            r"k\begin{bmatrix} 1 & -1 \\  -1  &  1  \end{bmatrix}",
            r"\begin{bmatrix}  \delta{u_1} \\   \delta{u_3}  \end{bmatrix}",
            color=RED,
        )
        spring1_k.next_to(spring1_equal_group, DOWN)
        self.play(ShowCreation(spring1_k))
        self.wait(2)

        F32_equal_two_spring = Tex(r"F_{32}", "=", r"k(\delta{u_2} - \delta{u_3})")
        F2_equal_two_spring = Tex(r"F_2", "=", r"k(\delta{u_3} - \delta{u_2})")
        spring2_equal_group = VGroup(F2_equal_two_spring, F32_equal_two_spring)
        spring2_equal_group.arrange(DOWN)

        self.play(ShowCreation(spring2_equal_group))
        self.wait(2)
        self.play(spring2_equal_group.animate.shift([5, 4, 0]))
        self.wait(2)

        spring2_k = Tex(
            r"\begin{bmatrix} F_{32} \\   F_2  \end{bmatrix} ",
            "=",
            r"k\begin{bmatrix} 1 & -1 \\  -1  &  1  \end{bmatrix}",
            r"\begin{bmatrix}   \delta{u_3} \\  \delta{u_2}  \end{bmatrix}",
            color=RED,
        ).next_to(spring2_equal_group, DOWN)
        self.play(ShowCreation(spring2_k))
        self.wait(2)

        self.play(spring1_k[0:7].animate.shift(np.array([2, -3.5, 0])))
        self.wait(2)
        self.play(spring2_k[0:7].animate.shift(np.array([-7, -4, 0])))
        self.wait(2)
        lhs_group = VGroup(
            spring1_k[0:7],
            spring2_k[0:7],
        )

        global_lhs = Tex(r"\begin{bmatrix} F_1 \\ F_{31}+F{32} \\   F_2  \end{bmatrix} ", color=RED).move_to(
            lhs_group.get_center()
        )

        self.play(ReplacementTransform(lhs_group, global_lhs))
        self.wait(2)

        self.play(spring1_k[8:17].animate.shift(np.array([3.7, -3.5, 0])))
        self.wait(2)
        self.play(spring2_k[8:17].animate.shift(np.array([-4.7, -4, 0])))
        self.wait(2)
        k_group = VGroup(
            spring1_k[8:17],
            spring2_k[8:17],
        )

        global_k = Tex(
            r"k\begin{bmatrix} 1 & -1 & 0 \\   -1 & 1+1 & -1 \\   0 & -1 & 1 \\     \end{bmatrix} ", color=RED
        ).move_to(k_group.get_center())

        self.play(ReplacementTransform(k_group, global_k))
        self.wait(2)

        self.play(spring1_k[17:].animate.shift(np.array([4.9, -3.5, 0])))
        self.wait(2)
        self.play(spring2_k[17:].animate.shift(np.array([-3.9, -4, 0])))
        self.wait(2)
        rhs_group = VGroup(
            spring1_k[17:],
            spring2_k[17:],
        )

        global_rhs = Tex(
            r"\begin{bmatrix} \delta{u_1} \\  \delta{u_3}  \\  \delta{u_2}   \end{bmatrix} ", color=RED
        ).move_to(rhs_group.get_center())

        self.play(ReplacementTransform(rhs_group, global_rhs))
        self.wait(2)

        self.play(
            spring1_k[7].animate.shift(np.array([3.5, -3.8, 0])),
            spring2_k[7].animate.shift(np.array([-6.5, -3.8, 0])),
        )
        self.wait(2)
        equal_group = VGroup(
            spring1_k[7],
            spring2_k[7],
        )

        global_equal = Tex("=", color=RED).move_to(
            equal_group.get_center(),
        )
        self.play(ReplacementTransform(equal_group, global_equal))
        self.wait(2)

        fem_equal_assemble = VGroup(
            global_lhs,
            global_k,
            global_rhs,
            global_equal,
        )

        fem_equal_two_spring = Tex(
            r"\begin{bmatrix}  F_1  \\ F_3\\  F_2 \end{bmatrix} = k\begin{bmatrix} 1 & -1 & 0 \\  -1  &  2k & -1 \\  0  &  -1 & 1 \end{bmatrix} \begin{bmatrix}  \delta{u_1} \\   \delta{u_3}  \\   \delta{u_2}  \end{bmatrix}",
            color=RED,
        )

        self.play(
            Uncreate(F1_equal_two_spring),
            Uncreate(F31_equal_two_spring),
            Uncreate(F2_equal_two_spring),
            Uncreate(F32_equal_two_spring),
            Uncreate(F3_equal_two_spring),
        )
        self.wait(2)

        self.play(ReplacementTransform(fem_equal_assemble, fem_equal_two_spring))
        self.wait(2)

        # ========================================================
        # ========================================================
        # ========================================================

        # u1边界假设
        u1_boundary_text = Tex(
            r"Introduce\enspace boundary:\enspace \delta{u_1}\enspace =\enspace 0m\enspace (boundary),\enspace F2=2kN,\enspace F3=1kN"
        ).to_corner(LEFT + UP)
        self.play(ShowCreation(u1_boundary_text))
        self.wait(2)

        fem_equal_two_spring_with_u1_boundary = Tex(
            r"\begin{bmatrix} 1\\  2 \end{bmatrix} = \begin{bmatrix} 2 & -1 \\  -1 & 1\end{bmatrix} \begin{bmatrix}  \delta{u_3}  \\   \delta{u_2}  \end{bmatrix}",
            color=RED,
        )

        self.play(ReplacementTransform(fem_equal_two_spring, fem_equal_two_spring_with_u1_boundary))
        self.wait(2)
        self.play(fem_equal_two_spring_with_u1_boundary.animate.shift([-5, 0, 0]))
        self.wait(2)

        result_with_u1_boundary = Tex(
            r"\begin{bmatrix}  \delta{u_3}  \\   \delta{u_2}  \end{bmatrix} = \begin{bmatrix}  3  \\   5  \end{bmatrix}"
        )
        self.play(ShowCreation(result_with_u1_boundary))
        self.wait(2)

        self.play(
            Uncreate(u1_boundary_text),
            Uncreate(result_with_u1_boundary),
            Uncreate(fem_equal_two_spring_with_u1_boundary),
            Uncreate(spring_group),
        )
        self.wait(2)

        # ========================================================
        # ========================================================
        # ========================================================

        # phase two

        # escalate 杆单元
        level_5_text = Tex(
            r"Level\enspace 5:\enspace spring\enspace element\enspace \rightarrow\enspace bar\enspace element",
            t2c={"bar\enspace element": RED},
        )
        level_5_text.align_to(level_4_text, LEFT + UP)
        self.play(ReplacementTransform(level_4_text, level_5_text))
        self.wait(2)

        questions = VGroup(
            Text("Where is coordinates?", t2c={"coordinates": RED}),
            Text("Where is Material Parameters?", t2c={"Material Parameters": RED}),
        ).arrange(DOWN)
        questions[1].shift(DOWN)

        self.play(ShowCreation(questions))
        self.wait(2)

        # self.wait(3)

        self.play(Uncreate(questions))
        self.wait(2)

        elem_start = [0, 0, 0]
        elem_end = [10, 0, 0]
        spring_elem = Spring3D(elem_start, elem_end, axis)
        cylinder_radius = 0.5
        cylinder = Group(
            Cylinder(radius=cylinder_radius, height=10, color=YELLOW),
            Circle(radius=cylinder_radius).move_to([0, 0, 5]).set_fill(YELLOW, opacity=1).set_style(stroke_width=0),
            Circle(radius=cylinder_radius).shift([0, 0, -5]).set_fill(YELLOW, opacity=1).set_style(stroke_width=0),
        )
        cylinder.rotate(-PI / 2, axis=UP, about_point=ORIGIN).move_to([5, 0, 0]),
        bar_elem = Group(
            cylinder,
            Sphere(radius=spring_elem[1].radius, color=RED).move_to(elem_start),
            Sphere(radius=spring_elem[1].radius, color=RED).move_to(elem_end),
        )

        # 绘制括号标签
        bar_brace = Brace(bar_elem, DOWN)
        bar_brace_text = Tex("L")
        # 更新位置
        always(bar_brace_text.next_to, bar_brace, DOWN)
        bar_brace_group = Group(
            bar_brace,
            bar_brace_text,
        )

        spring_node1 = spring_elem[1]
        spring_node2 = spring_elem[2]
        spring_left_arrow = Arrow(start=spring_node1.get_center() - np.array([1.5, 0, 0]), end=spring_node1)
        spring_left_arrow.set_style(stroke_color=RED)
        always(spring_left_arrow.next_to, spring_node1, LEFT)
        spring_right_arrow = Arrow(start=spring_node2.get_center() + np.array([1.5, 0, 0]), end=spring_node2)
        spring_right_arrow.set_style(stroke_color=RED)
        always(spring_right_arrow.next_to, spring_node2, RIGHT)
        spring_elem_with_arrow = Group(
            spring_elem,
            spring_left_arrow,
            spring_right_arrow,
        )

        bar_node1 = bar_elem[1]
        bar_node2 = bar_elem[2]
        bar_left_arrow = Arrow(start=bar_node1.get_center() - np.array([1.5, 0, 0]), end=bar_node1)
        bar_left_arrow.set_style(stroke_color=RED)
        always(bar_left_arrow.next_to, bar_node1, LEFT)
        bar_right_arrow = Arrow(start=bar_node2.get_center() + np.array([1.5, 0, 0]), end=bar_node2)
        bar_right_arrow.set_style(stroke_color=RED)
        always(bar_right_arrow.next_to, bar_node2, RIGHT)
        bar_elem_with_arrow = Group(
            bar_elem,
            bar_left_arrow,
            bar_right_arrow,
            bar_brace_group,
        )

        spring_to_bar_arrow = Arrow(start=np.array([0, 1, 0]), end=np.array([0, -1, 0]))
        spring_name_text = Text("Spring element")
        bar_name_text = Text("Bar element")
        phase_2_elem_group = Group(
            spring_name_text,
            spring_elem_with_arrow,
            spring_to_bar_arrow,
            bar_name_text,
            bar_elem_with_arrow,
        ).arrange(DOWN)

        phase_2_elem_group.move_to(ORIGIN).shift(RIGHT).shift(RIGHT).shift(RIGHT)
        self.play(ShowCreation(phase_2_elem_group))
        self.wait(2)

        single_spring_k.next_to(spring_left_arrow, LEFT)

        self.play(ShowCreation(single_spring_k))
        self.wait(2)

        # ========================================================
        # ========================================================
        # ========================================================

        single_bar_k = Tex(
            r"\begin{bmatrix}  F_1  \\  F_2 \end{bmatrix} = \frac{EA}{L}\begin{bmatrix}1 & -1 \\-1 & 1\end{bmatrix} \begin{bmatrix}  \delta{u_1} \\   \delta{u_2}  \end{bmatrix}",
            color=RED,
        )
        single_bar_k.next_to(bar_left_arrow, LEFT)
        self.play(ShowCreation(single_bar_k))
        self.wait(2)

        # 相机移到杆单元横截面

        self.play(cylinder.animate.rotate(PI/3,[0,1,0]))
        self.wait(2)
        cylinder[1].set_style(fill_color=RED)
        self.wait(3)
        cylinder[1].set_style(fill_color=YELLOW)
        self.play(cylinder.animate.rotate(-PI/3,[0,1,0]))
        self.wait(2)

        self.play(
            Uncreate(single_spring_k),
            Uncreate(spring_name_text),
            Uncreate(spring_elem_with_arrow),
            Uncreate(spring_to_bar_arrow),
            Uncreate(single_bar_k),
            Uncreate(bar_left_arrow),
            Uncreate(bar_right_arrow),
            Uncreate(bar_brace_group),
            Uncreate(bar_elem[1]),
            Uncreate(bar_elem[2]),
            Uncreate(bar_name_text),
            Uncreate(bar_brace),
            Uncreate(cylinder[1]),
            Uncreate(cylinder[2]),
        )
        self.wait(2)

        # ========================================================
        # ========================================================
        # ========================================================

        # escalate 桁架
        level_6_text = Tex(
            r"Level\enspace 6:\enspace bar\enspace element \rightarrow\enspace multiply\enspace bar\enspace elements(Truss)",
            t2c={"Truss": RED},
        )
        level_6_text.align_to(level_5_text, LEFT + UP)
        self.play(ReplacementTransform(level_5_text, level_6_text), bar_elem_with_arrow.animate.move_to(ORIGIN))
        self.wait(2)

        truss_node_scale = 2

        nodes = Group(
            # Sphere(color=RED).move_to(np.array([0, 0, 0])),
            Sphere(color=RED, radius=0.1)
            .move_to(np.array([0 * truss_node_scale, 0 * truss_node_scale, 0]))
            .shift([-4, -5, 0]),  # 0
            Sphere(color=RED, radius=0.1)
            .move_to(np.array([0 * truss_node_scale, 1 * truss_node_scale, 0]))
            .shift([-4, -5, 0]),  # 1
            Sphere(color=RED, radius=0.1)
            .move_to(np.array([0 * truss_node_scale, 2 * truss_node_scale, 0]))
            .shift([-4, -5, 0]),  # 2
            Sphere(color=RED, radius=0.1)
            .move_to(np.array([0 * truss_node_scale, 3 * truss_node_scale, 0]))
            .shift([-4, -5, 0]),  # 3
            Sphere(color=RED, radius=0.1)
            .move_to(np.array([0 * truss_node_scale, 4 * truss_node_scale, 0]))
            .shift([-4, -5, 0]),  # 4
            Sphere(color=RED, radius=0.1)
            .move_to(np.array([1 * truss_node_scale, 4 * truss_node_scale, 0]))
            .shift([-4, -5, 0]),  # 5
            Sphere(color=RED, radius=0.1)
            .move_to(np.array([2 * truss_node_scale, 4 * truss_node_scale, 0]))
            .shift([-4, -5, 0]),  # 6
            Sphere(color=RED, radius=0.1)
            .move_to(np.array([3 * truss_node_scale, 4 * truss_node_scale, 0]))
            .shift([-4, -5, 0]),  # 7
            Sphere(color=RED, radius=0.1)
            .move_to(np.array([3 * truss_node_scale, 3 * truss_node_scale, 0]))
            .shift([-4, -5, 0]),  # 8
            Sphere(color=RED, radius=0.1)
            .move_to(np.array([2 * truss_node_scale, 3 * truss_node_scale, 0]))
            .shift([-4, -5, 0]),  # 9
            Sphere(color=RED, radius=0.1)
            .move_to(np.array([1 * truss_node_scale, 3 * truss_node_scale, 0]))
            .shift([-4, -5, 0]),  # 0
            Sphere(color=RED, radius=0.1)
            .move_to(np.array([1 * truss_node_scale, 2 * truss_node_scale, 0]))
            .shift([-4, -5, 0]),  # 11
            Sphere(color=RED, radius=0.1)
            .move_to(np.array([1 * truss_node_scale, 1 * truss_node_scale, 0]))
            .shift([-4, -5, 0]),  # 12
            Sphere(color=RED, radius=0.1)
            .move_to(np.array([1 * truss_node_scale, 0 * truss_node_scale, 0]))
            .shift([-4, -5, 0]),  # 13
            Sphere(color=RED, radius=0.1)
            .move_to(np.array([4 * truss_node_scale, 3 * truss_node_scale, 0]))
            .shift([-4, -5, 0]),  # 14
        )

        elements = Group(
            Line(start=nodes[0], end=nodes[1], color=YELLOW),
            Line(start=nodes[1], end=nodes[2], color=YELLOW),
            Line(start=nodes[2], end=nodes[3], color=YELLOW),
            Line(start=nodes[3], end=nodes[4], color=YELLOW),
            Line(start=nodes[4], end=nodes[5], color=YELLOW),
            Line(start=nodes[5], end=nodes[6], color=YELLOW),
            Line(start=nodes[6], end=nodes[7], color=YELLOW),
            Line(start=nodes[7], end=nodes[8], color=YELLOW),
            Line(start=nodes[8], end=nodes[9], color=YELLOW),
            Line(start=nodes[9], end=nodes[10], color=YELLOW),
            Line(start=nodes[10], end=nodes[11], color=YELLOW),
            Line(start=nodes[11], end=nodes[12], color=YELLOW),
            Line(start=nodes[12], end=nodes[13], color=YELLOW),
            Line(start=nodes[13], end=nodes[0], color=YELLOW),
            Line(start=nodes[13], end=nodes[1], color=YELLOW),
            Line(start=nodes[12], end=nodes[1], color=YELLOW),
            Line(start=nodes[12], end=nodes[2], color=YELLOW),
            Line(start=nodes[11], end=nodes[2], color=YELLOW),
            Line(start=nodes[11], end=nodes[3], color=YELLOW),
            Line(start=nodes[10], end=nodes[3], color=YELLOW),
            Line(start=nodes[10], end=nodes[4], color=YELLOW),
            Line(start=nodes[10], end=nodes[5], color=YELLOW),
            Line(start=nodes[9], end=nodes[5], color=YELLOW),
            Line(start=nodes[9], end=nodes[6], color=YELLOW),
            Line(start=nodes[8], end=nodes[6], color=YELLOW),
            Line(start=nodes[7], end=nodes[14], color=YELLOW),
            Line(start=nodes[8], end=nodes[14], color=YELLOW),
        )

        self.play(
            cylinder[0].animate.scale(0.2).move_to(elements[4].get_center()),
        )
        self.wait(2)
        # self.play(
        # )
        self.remove(cylinder[0])
        self.add(elements[4])
        Truss_force_arrow = Arrow(
            start=nodes[14],
            end=nodes[14].get_center() - np.array([0, 2, 0]),
        )
        Truss_force_arrow.set_style(stroke_color=RED)
        Truss_force_text = Text("F", color=RED).next_to(Truss_force_arrow, DOWN)
        Truss_boundary = Line(start=nodes[0].shift(LEFT), end=nodes[13].shift(RIGHT), color=GREY)
        Truss_boundary_text = Text("Boundary", color=GREY).next_to(Truss_boundary, DOWN)

        Truss_model = Group(
            nodes,
            elements,
            Truss_force_arrow,
            Truss_force_text,
            Truss_boundary,
            Truss_boundary_text,
        )
        self.play(ShowCreation(Truss_model))
        self.wait(2)
        self.play(Truss_model.animate.scale(0.8).shift(LEFT * 5))
        self.wait(2)

        Truss_global_equal = Tex(
            r"\begin{bmatrix} F_{1} \\ F_{2} \\ \vdots \\ F_{n} \end{bmatrix} =",
            r"\begin{bmatrix} \frac{EA}{L_{11}} & \frac{EA}{L_{12}} & \cdots & \frac{EA}{L_{1n}} \\ \frac{EA}{L_{21}} & \frac{EA}{L_{22}} & \cdots & \frac{EA}{L_{2n}} \\ \vdots & \vdots & \ddots & \vdots \\ \frac{EA}{L_{n1}} & \frac{EA}{L_{n2}} & \cdots & \frac{EA}{L_{nn}} \end{bmatrix}",
            r"\begin{bmatrix} u_{1} \\ u_{2} \\ \vdots \\ u_{n} \end{bmatrix}",
        )
        Truss_global_equal.shift(RIGHT * 4).scale(1.2)
        self.play(ShowCreation(Truss_global_equal))
        self.wait(2)

        hello_world = Text("FEM Hello World!", color=RED).scale(2).shift(UP * 4)
        self.play(ShowCreation(hello_world))
        self.wait(2)

        self.wait()
